﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Xml;
using System.Xml.Linq;

using Perseus.Data;
using Perseus.Plugins;

using Hetymine.Executioner.Commands;
using Hetymine.Executioner.Controls;
using Hetymine.Executioner.Data;
using Hetymine.Executioner.Plugins;

namespace Hetymine.Executioner {
    /// <summary>
    /// Interaction logic for Config.xaml
    /// </summary>
    public partial class Config : Window {
        private IniFile _Config;
        
        private AppearanceConfigurator _AppearanceConfigurator;
        private BehaviourConfigurator _BehaviourConfigurator;
        private SoundsConfigurator _SoudnsConfigurator;
        private PluginConfigurator _PluginConfigurator;
        
        private Dictionary<string, List<ICommand>> _Commands;
        private CommandsConfigurator _CommandsConfigurator;

        private Dictionary<string, IConfigurator<IniFile>> _PluginConfigurators;

        public Config() {
            InitializeComponent();

            this._Config = Executioner.Config.Clone() as IniFile;            
            this._Commands = this.Commands_Clone();

            // Only show unknown tree item if unknown items exist
            if (this._Commands.ContainsKey("Unknown")) {
                TreeViewItem unknownTreeViewItem = new TreeViewItem();
                unknownTreeViewItem.Header = "Unknown";
                unknownTreeViewItem.Name = "cCommandsUnknown";
                this.cCommands.Items.Insert(0, unknownTreeViewItem);
            }
                       
            // Add command types to commands tree item
            var plugins = from p in Executioner.PluginService.Plugins
                          where p.Instance is CommandPlugin
                          select p;
            
            foreach (PluginInstance<Plugin> p in plugins) {
                TreeViewItem pluginTreeViewItem = new TreeViewItem();
                pluginTreeViewItem.Header = p.Instance.PluginInfo.Name;
                pluginTreeViewItem.Tag = p.Name;

                this.cCommands.Items.Add(pluginTreeViewItem);                
            }
                        
            // Add plugin configuration types to plugin tree items
            this._PluginConfigurators = new Dictionary<string, IConfigurator<IniFile>>();
            plugins = from p in Executioner.PluginService.Plugins
                          where p.Instance is IConfigurable<IniFile>
                          select p;

            foreach (PluginInstance<Plugin> p in plugins) {
                this._PluginConfigurators.Add(p.FullName, null);

                TreeViewItem pluginTreeViewItem = new TreeViewItem();
                pluginTreeViewItem.Header = p.Instance.PluginInfo.Name;
                pluginTreeViewItem.Tag = p.FullName;

                this.cPlugins.Items.Add(pluginTreeViewItem);

                //if (p.Instance is CommandPlugin) {                    
                //    this.cCommandPlugins.Items.Add(pluginTreeViewItem);
                //}
                //else if (p.Instance is TriggerPlugin) {
                //    this.cTriggerPlugins.Items.Add(pluginTreeViewItem);
                //}
                //else {
                //    this.cOtherPlugins.Items.Add(pluginTreeViewItem);
                //}
            }

            // Hide or show plugin navigation items
            //bool show = false;
            //if (this.cCommandPlugins.Items.Count == 0) {
            //    this.cCommandPlugins.Visibility = Visibility.Collapsed;
            //}
            //else {
            //    show = true;
            //}
            //if (this.cTriggerPlugins.Items.Count == 0) {
            //    this.cTriggerPlugins.Visibility = Visibility.Collapsed;
            //}
            //else {
            //    show = true;
            //}
            //if (this.cOtherPlugins.Items.Count == 0) {
            //    this.cOtherPlugins.Visibility = Visibility.Collapsed;
            //}
            //else {
            //    show = true;
            //}
            //if (!show) {
            //    this.cPlugins.Visibility = Visibility.Collapsed;
            //}

            if (this.cPlugins.Items.Count == 0) {
                this.cNavigation.Items.Remove(this.cPlugins);
            }

            // Setup configuration events
            this.cNavigation.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(Navigation_SelectedItemChanged);

            this.cCancel.Click += new RoutedEventHandler(Cancel_Click);
            this.cOkay.Click += new RoutedEventHandler(Okay_Click);
            this.Closing += new System.ComponentModel.CancelEventHandler(Config_Closing);

            this.SelectNavigationItem(this.cAppearance);

        }                
        #region Events
        private void Okay_Click(object sender, RoutedEventArgs e) {
            this.Save();
            this.Close();
        }
        private void Cancel_Click(object sender, RoutedEventArgs e) {
            this.Close();
        }
        private void Config_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
            // Clean up before closing
            if (this._CommandsConfigurator != null) {
                this._CommandsConfigurator.cConfigurator.Content = null;
            }
            this.cConfigurator.Child = null;
        }        
        #endregion
        #region Saving
        private void Save() {
            this._Config.Save(true);

            XmlWriterSettings xws = new XmlWriterSettings();
            xws.Encoding = System.Text.Encoding.UTF8;
            xws.Indent = true;
            xws.IndentChars = "    ";
            xws.NewLineChars = Environment.NewLine;
            xws.NewLineHandling = NewLineHandling.Replace;
            xws.OmitXmlDeclaration = true;

            string fileName = AppDomain.CurrentDomain.BaseDirectory + "commands.xml";
            XmlWriter xw = XmlWriter.Create(fileName, xws);

            XElement xe = new XElement("Executioner");
            xe.Add(new XAttribute("Version", "1.1"));

            // Add command xelements
            XElement csxe = new XElement("Commands");
            foreach (List<ICommand> commands in this._Commands.Values) {
                foreach (ICommand command in commands) {
                    XElement cxe = command.Save();
                    if (cxe != null) {
                        csxe.Add(cxe);
                    }
                }
            }
            xe.Add(csxe);
            
            xe.WriteTo(xw);

            xw.Close();
        }
        #endregion
        #region Navigation
        private void Navigation_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) {            
            this.SelectNavigationItem(e.NewValue as TreeViewItem);
        }
        private void SelectNavigationItem(TreeViewItem item) {
            switch (item.Name) {
                case "cAppearance":
                    if (this._AppearanceConfigurator == null) {
                        this._AppearanceConfigurator = new AppearanceConfigurator();
                        this._AppearanceConfigurator.InitializeConfig(this._Config);
                    }
                    this.cConfigurator.Child = this._AppearanceConfigurator;
                    break;
                case "cBehaviour":
                    if (this._BehaviourConfigurator == null) {
                        this._BehaviourConfigurator = new BehaviourConfigurator();
                        this._BehaviourConfigurator.InitializeConfig(this._Config);
                    }
                    this.cConfigurator.Child = this._BehaviourConfigurator;
                    break;
                case "cSounds":
                    if (this._SoudnsConfigurator == null) {
                        this._SoudnsConfigurator = new SoundsConfigurator();
                        this._SoudnsConfigurator.InitializeConfig(this._Config);
                    }
                    this.cConfigurator.Child = this._SoudnsConfigurator;
                    break;
                case "cCommands":
                    this.InitializeCommandConfigurator(string.Empty);
                    break;
                case "cCommandsUnknown":
                    this.InitializeCommandConfigurator("Unknown");
                    break;
                case "cCommandsTrigger":
                    this.InitializeCommandConfigurator("Trigger");
                    break;
                case "cPlugins":
                    if (this._PluginConfigurator == null) {
                        this._PluginConfigurator = new PluginConfigurator();
                        this._PluginConfigurator.InitializeConfig(Executioner.PluginService.Plugins);
                    }
                    this.cConfigurator.Child = this._PluginConfigurator;
                    break;
                default:
                    if (item.Parent is TreeViewItem) {
                        switch (((TreeViewItem)item.Parent).Name) {
                            case "cCommands":
                                this.InitializeCommandConfigurator(item.Tag.ToString());
                                return;
                            case "cPlugins":
                            //case "cCommandPlugins":
                            //case "cTriggerPlugins":
                            //case "cOtherPlugins":
                                InitializePluginConfigurator(item.Tag.ToString());
                                return;
                        }
                    }
                    this.cConfigurator.Child = null;
                    break;
            }
        }
        #endregion
        #region Commands
        private void InitializeCommandConfigurator(string type) {
            if (this._CommandsConfigurator == null) {
                this._CommandsConfigurator = new CommandsConfigurator();
                this._CommandsConfigurator.InitializeConfig(this._Commands);
            }
            this._CommandsConfigurator.CommandTypeFilter(type);
            this.cConfigurator.Child = this._CommandsConfigurator;
        }
        private Dictionary<string, List<ICommand>> Commands_Clone() {
            Dictionary<string, List<ICommand>> cmds = new Dictionary<string, List<ICommand>>();

            foreach (string type in Executioner.Instance.Commands.Keys) {
                cmds[type] = this.Commands_Clone(type);
            }

            return cmds;
        }
        private List<ICommand> Commands_Clone(string type) {
            List<ICommand> cmds = new List<ICommand>();
            foreach (ICommand c in Executioner.Instance.Commands[type]) {
                cmds.Add(c.Clone() as ICommand);
            }
            return cmds;
        }
        #endregion
        #region Plugins
        private void InitializePluginConfigurator(string type) {
            if (this._PluginConfigurators[type] == null) {
                this._PluginConfigurators[type] = ((IConfigurable<IniFile>)Executioner.PluginService[type].Instance).Configurator;
                this._PluginConfigurators[type].InitializeConfig(this._Config);
            }
            this.cConfigurator.Child = this._PluginConfigurators[type] as UserControl;
        }
        #endregion
    }
}
